package com.iteaj.util.json.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.iteaj.util.core.UtilsException;
import com.iteaj.util.core.UtilsType;
import com.iteaj.util.json.Json;
import com.iteaj.util.json.JsonArray;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * create time: 2018/9/20
 *
 * @author iteaj
 * @since 1.0
 */
public class JacksonArray implements JsonArray {

    private ArrayNode nodes;
    private ObjectMapper mapper;

    public JacksonArray(ArrayNode nodes, ObjectMapper mapper) {
        this.nodes = nodes;
        this.mapper = mapper;
    }

    @Override
    public ArrayNode original() {
        return this.nodes;
    }

    @Override
    public int size() {
        return original().size();
    }

    @Override
    public Json getJson(int index) {
        JsonNode node = this.original().get(index);
        return node == null ? null : new Jackson((ObjectNode) node, mapper);
    }

    @Override
    public JsonArray getJsonArray(int index) {
        JsonNode node = this.original().get(index);
        return node == null ? null : new JacksonArray((ArrayNode) node, mapper);
    }

    @Override
    public <T> ArrayList<T> toList(Class<T> clazz) {
        CollectionType type = mapper.getTypeFactory()
                .constructCollectionType(ArrayList.class, clazz);

        return (ArrayList<T>) mapper.convertValue(original(), type);
    }

    @Override
    public <E> Iterator<E> iterator() {

        Iterator<JsonNode> iterator = original().iterator();
        List<E> list = new ArrayList();
        iterator.forEachRemaining((item) -> {
                try {
                    if(item instanceof NumericNode) {
                        list.add((E) mapper.treeToValue(item, Number.class));
                    } else if(item instanceof BooleanNode) {
                        list.add((E) mapper.treeToValue(item, Boolean.class));
                    } else if(item instanceof ObjectNode) {
                        list.add((E) new Jackson((ObjectNode)item, mapper));
                    } else if(item instanceof ArrayNode) {
                        list.add((E) new JacksonArray((ArrayNode) item, mapper));
                    } else{
                        list.add((E) item.asText());
                    }

                } catch (JsonProcessingException e) {
                    throw new UtilsException(e.getMessage(), e, UtilsType.JSON);
                }
        });

        return list.iterator();
    }

    @Override
    public <T> T toArray(Class<T> arrayType) {
        try {
            if(!arrayType.isArray())
                throw new UtilsException("数组类型错误 e.g Integer[].class", UtilsType.JSON);

            return mapper.treeToValue(original(), arrayType);
        } catch (JsonProcessingException e) {
            throw new UtilsException("反序列化JsonArray到Java对象失败", e, UtilsType.JSON);
        }
    }

    @Override
    public String toJsonString() {
        try {
            return mapper.writeValueAsString(original());
        } catch (JsonProcessingException e) {
            throw new UtilsException(e.getMessage(), e, UtilsType.JSON);
        }
    }
}
